/*
common resources(frames, texures, sounds) are cached in "entry lists"
these lists are global for the application and its members should be fred with caution
*/
#include "io.h"

#include <windows.h>	//
#include <gl/gl.h>		// better done in renderer
#include <gl/glu.h>		// better done in renderer
#include <list>
using namespace std;

#include "level.h"
#include "platform.h"
#include "frame.h"
#include "animation.h"
#include "hunter.h"
#include "camera.h"
#include "entry.h"
#include "texture.h"
#include "zomby.h"
#include "slope.h"
#include "audio.h"
#include "tga.h"
#include "circle.h"
#include "source.h"
#include "rect.h"
#include "polygon.h"
#include "tools.h"
#include "audio.h"
#include "fx.h"
#include "game.h"
#include "ai.h"
#include "kolobok.h"
#include "cloud.h"
#include "respawn.h"
//#include "object.h"
#include "bird.h"
#include "globals.h"

list<Entry*> frames;
list<Entry*> textures;
list<Entry*> sounds;
//list<Entry*> zombies;
Fx** effects =NULL;

char data_path[256];
char animations_path[256];
char floors_path[256];
char frames_path[256];
char platforms_path[256];
char sprites_path[256];
char textures_path[256];
char slopes_path[256];
char circles_path[256];
char characters_path[256];
char sounds_path[256];
char sources_path[256];
char effects_path[256];
char clouds_path[256];
char composites_path[256];
char polygons_path[256];
char ai_path[256];
char respawns_path[256];

Platform* loadPlatform(char* name, bool cache);
Platform* loadFloor(char* name, bool cache);
Frame* loadFrame(char* name, bool cache);
Zomby* loadZomby(char* name, bool cache);
Slope* loadSlope(char* name, bool cache);
Circle* loadCircle(char* name, bool cache);
//Source* loadSource(char* name, bool cahce);
Kolobok* loadKolobok(char* name, bool cache);
Cloud* loadCloud(char* name, bool cache);
Polygon2* loadPolygon(char* name, bool cache);
Texture* loadTexture(char* name, bool cache);
AI* loadAI(char* name, bool cache);
Respawn* loadRespawn(char* name, bool cache);

int max_respawns;
int max_platforms;
int max_floors;

void createEffects(){

//	effects =new Fx[2];
//	effects[0] =
}

bool loadSound(char* name, unsigned int* bfr, bool cache);
unsigned int loadTextureTGA(char* name);

int getMaterial(char* material){

	if(strcmp(material, "ground")==0){
		return MAT_GROUND;
	}
	else if(strcmp(material, "concrete")==0){
		return MAT_CONCRETE;
	}
	else if(strcmp(material, "wood")==0){
		return MAT_WOOD;
	}
	else if(strcmp(material, "metal")==0){
		return MAT_METAL;
	}

	return 0;
}

void* findEntry(list<Entry*>* l, char* name){

	list<Entry*>::iterator iter;

	for(iter = l->begin(); iter != l->end(); iter++){

		if(!strcmp((*iter)->name, name))
			return (*iter)->pointer;
	}

	return NULL;
}

bool loadComposite(char* name, Level* level, float x, float y, bool cache){

	char buffer[256];
	char errmsg[512];
	Platform* platform;
//	Platform* floor;	//? no need -platform does all
//	Zomby* zomby;
	Slope* slope;
	Circle* circle;
	Source* source;
	//	Kolobok* kolobok;
//	Cloud* cloud;
	Polygon2* polygon;
	Bird* bird;
	Audio* audio =Audio::Instance();

	if(!name)
		return NULL;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, composites_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return false;
	}

	while(!fs.eof()){

		fs >>buffer;
		if(strcmp(buffer, "PLATFORM")==0)	// loading platform
		{			
			level->platforms_num++;
			if(level->platforms_num >max_platforms){
				level->platforms_num =max_platforms;
				fs.close();
				delete level;
				sprintf (errmsg, "Error: Too many platforms max allowed: (%d)", max_platforms);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>buffer;
			level->platforms[level->platforms_num-1] =loadPlatform(buffer, cache);
			if(!level->platforms[level->platforms_num-1]){

				fs.close();
				delete level;
				sprintf (errmsg, "Error: Failed to load platform (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>level->platforms[level->platforms_num-1]->position->x;
			fs >>level->platforms[level->platforms_num-1]->position->y;
			fs >>level->platforms[level->platforms_num-1]->layer;

			level->platforms[level->platforms_num-1]->position->x +=x;
			level->platforms[level->platforms_num-1]->position->y +=y;
		}
		else
		if(strcmp(buffer, "POLYGON")==0)	// loading polygon
		{
			fs >>buffer;	// polygon's name
			polygon =loadPolygon(buffer, cache);
			if(!polygon){

				fs.close();
				sprintf (errmsg, "Error: Failed to load polygon (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			fs >>polygon->position->x;
			fs >>polygon->position->y;
			fs >>polygon->layer;

			polygon->position->x +=x;
			polygon->position->y +=y;
			level->polygons.push_back(polygon);
		}
		else 
		if(strcmp(buffer, "CIRCLE")==0)
		{
			fs >>buffer;	// name
			circle =loadCircle(buffer, cache);
			if(!circle){

				fs.close();
				sprintf (errmsg, "Error: Failed to load circle (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			fs >>circle->position->x;
			fs >>circle->position->y;
			fs >>circle->layer;

			circle->position->x +=x;
			circle->position->y +=y;
			level->circles.push_back(circle);
		}
		else
		if(strcmp(buffer, "IMAGE")==0)	// loading image
		{			
			fs >>buffer;	// platform name
			platform =loadPlatform(buffer, cache);
			if(!platform){

				fs.close();
				sprintf (errmsg, "Error: Failed to load image (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			platform->position =new Point2;
			fs >>platform->position->x;
			fs >>platform->position->y;
			fs >>platform->layer;

			platform->position->x +=x;
			platform->position->y +=y;
			level->images.push_back(platform);
		}
		else
		if(strcmp(buffer, "SOURCE")==0)
		{			
			fs >>buffer;
			source =loadSource(buffer, cache);
			if(!source){

				fs.close();
				sprintf (errmsg, "Error: Failed to load source (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			fs >>source->x;
			fs >>source->y;

			source->x +=x;
			source->y +=y;

			audio->setSource(source->id, source->buffer, source->x, source->y, source->z, source->gain, source->loop);
			level->sources.push_back(source);
		}
		else
		if(strcmp(buffer, "ITEM")==0)	// loading item
		{
			fs >>buffer;
			platform =loadPlatform(buffer, cache);
			if(!platform){

				fs.close();
				sprintf (errmsg, "Error: Failed to load item (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}

			fs >>platform->position->x;
			fs >>platform->position->y;
			fs >>platform->layer;

			platform->position->x +=x;
			platform->position->y +=y;
			level->items.push_back(platform);
		}
		else
		if(strcmp(buffer, "FLOOR")==0)	// loading floor
		{			
			level->floors_num++;
			if(level->floors_num >max_floors){
				level->floors_num =max_floors;
				fs.close();
				delete level;
				sprintf (errmsg, "Error: Too many floors max allowed: (%d)", max_floors);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>buffer;
			level->floors[level->floors_num-1] =loadFloor(buffer, cache);
			if(!level->floors[level->floors_num-1]){

				fs.close();
				delete level;
				sprintf (errmsg, "Error: Failed to load floor (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>level->floors[level->floors_num-1]->position->x;
			fs >>level->floors[level->floors_num-1]->position->y;
			fs >>level->floors[level->floors_num-1]->layer;

			level->floors[level->floors_num-1]->position->x +=x;
			level->floors[level->floors_num-1]->position->y +=y;
		}
		else
		if(strcmp(buffer, "SLOPE")==0)
		{
			fs >>buffer;	// floor's name
			slope =loadSlope(buffer, cache);
			if(!slope){

				fs.close();
				sprintf (errmsg, "Error: Failed to load slope (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}

			fs >>slope->position->x;
			fs >>slope->position->y;
			fs >>slope->layer;

			slope->position->x +=x;
			slope->position->y +=y;
			level->slopes.push_back(slope);
		}
		else
		if(strcmp(buffer, "RESPAWN")==0)	// loading respawns
		{
			level->respawns_num++;
			if(level->respawns_num >max_respawns){
				level->respawns_num =max_respawns;
				sprintf (errmsg, "Error: Too many respawn points (%d)", max_respawns+1);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			fs >>buffer;
			level->respawns[level->respawns_num-1] =loadRespawn(buffer, cache);
			if(!level->respawns[level->respawns_num-1]){

				fs.close();
				sprintf (errmsg, "Error: Failed to load respawn (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			// get position
			fs >>level->respawns[level->respawns_num-1]->position->x;
			fs >>level->respawns[level->respawns_num-1]->position->y;
			// update coordinates
			level->respawns[level->respawns_num-1]->position->x +=x;
			level->respawns[level->respawns_num-1]->position->y +=y;
			level->respawns[level->respawns_num-1]->ai->xLo +=level->respawns[level->respawns_num-1]->position->x;
			level->respawns[level->respawns_num-1]->ai->xHi +=level->respawns[level->respawns_num-1]->position->x;

			fs >>level->respawns[level->respawns_num-1]->layer;
		}
		else 
		if(strcmp(buffer, "BIRD")==0){	// load bird
		
			fs >>buffer;	// bird's name
			bird =loadBird(buffer, cache);
			if(!bird){

				fs.close();
				sprintf (errmsg, "Error: Failed to load bird (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
//			bird->setState(STATE_STILL, 0);
			bird->setStill(0);
			bird->orientation->y =0;
			bird->orientation->x =-1;

			fs >>bird->position->x;
			fs >>bird->position->y;
			bird->position->x +=x;
			bird->position->y +=y;

			delete bird->ai;
			fs >>buffer;
			bird->ai =loadAI(buffer, cache);
			if(!bird->ai){

				fs.close();
				delete bird;
				sprintf (errmsg, "Error: Failed to load ai (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return false;
			}
			bird->ai->xHi +=bird->position->x;
			bird->ai->xLo +=bird->position->x;
			
			fs >>bird->layer;
			bird->active =true; 
			level->birds.push_back(bird);				
		}
	}

	return true;
}

Level* loadLevel(char* name, bool cache){

	char buffer[256];
	Platform* platform;
//	Platform* floor;	//?  no neen - it is platform
	Level* level;
	Zomby* zomby;
	Slope* slope;
	Circle* circle;
	Source* source;
	Kolobok* kolobok;
	Cloud* cloud;
	Polygon2* polygon;
	Bird* bird;
	int num, i;
	float x, y;
	char errmsg[512];
	Audio* audio =Audio::Instance();

	if(!name)
		return NULL;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, data_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}
	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // level
	if(strcmp(buffer, "level")){
		fs.close();
		return NULL;
	}

	fs >>buffer; // MAX_PLATFORMS
	if(strcmp(buffer, "MAX_PLATFORMS")){
		fs.close();
		return NULL;
	}
	fs >>max_platforms;

	fs >>buffer; // MAX_FLOORS
	if(strcmp(buffer, "MAX_FLOORS")){
		fs.close();
		return NULL;
	}
	fs >>max_floors;

	fs >>buffer; // MAX_RESPAWN
	if(strcmp(buffer, "MAX_RESPAWNS")){
		fs.close();
		return NULL;
	}
	fs >>max_respawns;

	level =new Level;
	level->respawns =new Respawn*[max_respawns];
	level->platforms =new Platform*[max_platforms];
	level->floors =new Platform*[max_floors];
	while(!fs.eof()){

		fs >>buffer;
		if(strcmp(buffer, "ZOMBIES")==0)	// loading zombies
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// zomby's name
				zomby =loadZomby(buffer, cache);
				if(!zomby){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load zomby (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
//				zomby->setState(STATE_FALL, 0);
				zomby->setFall(0);
				zomby->orientation->y =0;
				zomby->orientation->x =-1;

				fs >>zomby->position->x;
				fs >>zomby->position->y;

				fs >>buffer;
				zomby->ai =loadAI(buffer, cache);
				if(!zomby->ai){

					fs.close();
					delete zomby;
					delete level;
					sprintf (errmsg, "Error: Failed to load ai (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}

				fs >>zomby->layer;
				zomby->active =true;

				level->zombies.push_back(zomby);				
			}
		}
		else
		if(strcmp(buffer, "BIRDS")==0)	// loading birds
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// bird's name
				bird =loadBird(buffer, cache);
				if(!bird){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load bird (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
//				bird->setState(STATE_STILL, 0);
				bird->setStill(0);
				bird->orientation->y =0;
				bird->orientation->x =-1;

				fs >>bird->position->x;
				fs >>bird->position->y;

				delete bird->ai;
				fs >>buffer;
				bird->ai =loadAI(buffer, cache);
				if(!bird->ai){

					fs.close();
					delete bird;
					delete level;
					sprintf (errmsg, "Error: Failed to load ai (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>bird->layer;

				bird->active =true; 
				level->birds.push_back(bird);				
			}
		}
		else
		if(strcmp(buffer, "COMPOSITE")==0)	// loading composite object
		{
			fs >>buffer;
			fs >>x;
			fs >>y;
			if(!loadComposite(buffer, level, x, y, cache)){

				fs.close();
				delete level;
				sprintf (errmsg, "Error: Failed to load composite (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
		}
		else
		if(strcmp(buffer, "POLYGONS")==0)	// loading polygon
		{
			fs >>num;

			for(i=0; i<num; i++){

				fs >>buffer;	// polygon's name
				polygon =loadPolygon(buffer, cache);
				if(!polygon){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load polygon (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>polygon->position->x;
				fs >>polygon->position->y;
				fs >>polygon->layer;

				level->polygons.push_back(polygon);
			}
		}
		else
		if(strcmp(buffer, "RESPAWNS")==0)	// loading respawns
		{
			fs >>num;

			for(i=0; i<num; i++){

				level->respawns_num++;
				if(level->respawns_num >max_respawns){
					level->respawns_num =max_respawns;
					fs.close();
					delete level;
					sprintf (errmsg, "Error: Too many respawn points max allowed: (%d)", max_respawns);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				level->respawns[level->respawns_num-1] =loadRespawn(buffer, cache);
				if(!level->respawns[level->respawns_num-1]){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load respawn (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>level->respawns[level->respawns_num-1]->position->x;
				fs >>level->respawns[level->respawns_num-1]->position->y;

				level->respawns[level->respawns_num-1]->ai->xHi +=level->respawns[level->respawns_num-1]->position->x;
				level->respawns[level->respawns_num-1]->ai->xLo +=level->respawns[level->respawns_num-1]->position->x;
				fs >>level->respawns[level->respawns_num-1]->layer;
			}
		}
		else
		if(strcmp(buffer, "PLATFORMS")==0)	// loading platforms
		{
			fs >>num;

			for(i=0; i<num; i++){

				level->platforms_num++;
				if(level->platforms_num >max_platforms){
					level->platforms_num =max_platforms;
					fs.close();
					delete level;
					sprintf (errmsg, "Error: Too many platforms max allowed: (%d)", max_platforms);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>buffer;
				level->platforms[level->platforms_num-1] =loadPlatform(buffer, cache);
				if(!level->platforms[level->platforms_num-1]){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load platform (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>level->platforms[level->platforms_num-1]->position->x;
				fs >>level->platforms[level->platforms_num-1]->position->y;
				fs >>level->platforms[level->platforms_num-1]->layer;
			}
		}
		else
		if(strcmp(buffer, "FLOORS")==0)	// loading floors
		{
			fs >>num;

			for(i=0; i<num; i++){

				level->floors_num++;
				if(level->floors_num >max_floors){
					level->floors_num =max_floors;
					fs.close();
					delete level;
					sprintf (errmsg, "Error: Too many floors max allowed: (%d)", max_floors);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>buffer;
				level->floors[level->floors_num-1] =loadFloor(buffer, cache);
				if(!level->floors[level->floors_num-1]){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load floor (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>level->floors[level->floors_num-1]->position->x;
				fs >>level->floors[level->floors_num-1]->position->y;
				fs >>level->floors[level->floors_num-1]->layer;
			}
		}
		else
		if(strcmp(buffer, "MAX_ZOMBIES")==0)
		{
			fs >>level->max_zombies;
			fs >>buffer;	// zomby's name
			for(i=0; i<level->max_zombies; i++){

				zomby =loadZomby(buffer, cache);
				if(!zomby){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load zomby (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				zomby->active =false;

				level->zombies.push_back(zomby);				
			}
		}
		else
		if(strcmp(buffer, "KOLOBOKS")==0)	// loading koloboks
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// kolobok's name
				kolobok =loadKolobok(buffer, cache);
				if(!kolobok){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load kolobok (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
//				kolobok->setState(STATE_FALL, 0);
				kolobok->setFall(0);
				fs >>kolobok->position->x;
				fs >>kolobok->position->y;

				fs >>kolobok->ai->xLo;
				fs >>kolobok->ai->xHi;

				fs >>kolobok->layer;

				level->koloboks.push_back(kolobok);
			}
		}
		else if(strcmp(buffer, "RECT")==0)
		{
			level->rect =new Rect;

			fs >>buffer;
			fs >>level->rect->xLo;
			fs >>buffer;
			fs >>level->rect->yLo;
			fs >>buffer;
			fs >>level->rect->xHi;
			fs >>buffer;
			fs >>level->rect->yHi;
		}
		else if(strcmp(buffer, "SKY")==0)
		{
			level->sky =new Rect;

			fs >>buffer;
			fs >>level->sky->xLo;
			fs >>buffer;
			fs >>level->sky->yLo;
			fs >>buffer;
			fs >>level->sky->xHi;
			fs >>buffer;
			fs >>level->sky->yHi;

			fs >>buffer;
			fs >>level->r_xLo_yLo;
			fs >>level->g_xLo_yLo;
			fs >>level->b_xLo_yLo;

			fs >>buffer;
			fs >>level->r_xLo_yHi;
			fs >>level->g_xLo_yHi;
			fs >>level->b_xLo_yHi;

			fs >>buffer;
			fs >>level->r_xHi_yHi;
			fs >>level->g_xHi_yHi;
			fs >>level->b_xHi_yHi;

			fs >>buffer;
			fs >>level->r_xHi_yLo;
			fs >>level->g_xHi_yLo;
			fs >>level->b_xHi_yLo;
		}
		else 
		if(strcmp(buffer, "CLOUDS")==0)
		{
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// cloud's name
				cloud =loadCloud(buffer, cache);
				if(!cloud){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load cloud (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				
				fs >>cloud->position->x;
				fs >>cloud->position->y;
				fs >>cloud->z;

				level->clouds.push_back(cloud);
			}
		}
		else if(strcmp(buffer, "GRAVITY")==0)
		{
			fs >>level->gravity;
		}
		else if(strcmp(buffer, "LAYERS")==0)
		{
			fs >>level->layers;
		}
		else if(strcmp(buffer, "SLOPES")==0)
		{
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// floor's name
				slope =loadSlope(buffer, cache);
				if(!slope){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load slope (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}

				fs >>slope->position->x;
				fs >>slope->position->y;
				fs >>slope->layer;

				level->slopes.push_back(slope);
			}
		}
		else if(strcmp(buffer, "DEADLINE")==0)
		{
			fs >>level->deadline;
		}
		else if(strcmp(buffer, "ITEMS")==0)	// loading platforms
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// platform name
				platform =loadPlatform(buffer, cache);
				if(!platform){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load item (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}

				fs >>platform->position->x;
				fs >>platform->position->y;
				fs >>platform->layer;

				level->items.push_back(platform);
			}
		}
		else if(strcmp(buffer, "IMAGES")==0)	// loading platforms
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// platform name
				platform =loadPlatform(buffer, cache);
				if(!platform){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load image (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>platform->position->x;
				fs >>platform->position->y;
				fs >>platform->layer;

				level->images.push_back(platform);
			}
		}
		else if(strcmp(buffer, "PLAYER")==0)
		{
			fs >>level->player_position_x;
			fs >>level->player_position_y;
			fs >>level->player_layer;
		}
		else if(strcmp(buffer, "CIRCLES")==0)
		{
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;	// name
				circle =loadCircle(buffer, cache);
				if(!circle){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load circle (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>circle->position->x;
				fs >>circle->position->y;
				fs >>circle->layer;

				level->circles.push_back(circle);
			}
		}
		else if(strcmp(buffer, "FINISH")==0)
		{			
			fs >>buffer;	// platform name
			level->finish =loadPlatform(buffer, cache);
			if(!level->finish){

				fs.close();
				delete level;
				sprintf (errmsg, "Error: Failed to load finish (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>level->finish->position->x;
			fs >>level->finish->position->y;
			fs >>level->finish->layer;
		}
		else if(strcmp(buffer, "SOURCES")==0)
		{			
			fs >>num;
			for(i=0; i<num; i++){

				fs >>buffer;
				source =loadSource(buffer, cache);
				if(!source){

					fs.close();
					delete level;
					sprintf (errmsg, "Error: Failed to load source (%s)", buffer);
					MessageBox (NULL, errmsg, NULL, MB_OK);	
					return NULL;
				}
				fs >>source->x;
				fs >>source->y;

				audio->setSource(source->id, source->buffer, source->x, source->y, source->z, source->gain, source->loop);
				level->sources.push_back(source);
			}
		}
		else if(strcmp(buffer, "SOURCE_WIN")==0)
		{			
			fs >>buffer;
			source =loadSource(buffer, cache);
			if(!source){

				fs.close();
				delete level;
				sprintf (errmsg, "Error: Failed to load source (%s)", buffer);
				MessageBox (NULL, errmsg, NULL, MB_OK);	
				return NULL;
			}
			fs >>source->x;
			fs >>source->y;

			audio->genSource(&(source->id));
			level->src_win =source;
		}
	}

    fs.close();
	return level;
}

AI* loadAI(char* name, bool cache){

	AI* ai;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, ai_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "ai")){
		fs.close();
		return NULL;
	}
	ai =new AI;

	while(!fs.eof()){

		fs >>buffer;
		if(strcmp(buffer, "TYPE")==0)
		{			
			fs >>buffer;	//unused
		}
		else
		if(strcmp(buffer, "X_LO")==0)
		{			
			fs >>ai->xLo;
		}
		else
		if(strcmp(buffer, "X_HI")==0)
		{			
			fs >>ai->xHi;
		}
		else
		if(strcmp(buffer, "MAX_TIME")==0)
		{			
			fs >>ai->max_time;
		}
		else
		if(strcmp(buffer, "ATTACK_PROXIMITY")==0)
		{			
			fs >>ai->attack_proximity;
		}
	}

	return ai;
}

Respawn* loadRespawn(char* name, bool cache){

	Respawn* respawn;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, respawns_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "respawn")){
		fs.close();
		return NULL;
	}
	respawn =new Respawn;
	respawn->position =new Point2;

	fs >>buffer; // AI
	if(strcmp(buffer, "AI")){
		fs.close();
		delete respawn;
		return NULL;
	}
	fs >>buffer;
	respawn->ai =loadAI(buffer, cache);
	if(!respawn->ai){
		fs.close();
		delete respawn;
		return NULL;
	}

	return respawn;
}

Platform* loadPlatform(char* name, bool cache){

	Platform* platform;
	char buffer[256];
//	Entry* entry;

	// search if this platform exists
//	platform =(Platform*)findEntry(&platforms, name);
//	if(platform)
//		return platform;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, platforms_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "platform")){
		fs.close();
		return NULL;
	}
	platform =new Platform;
	platform->position =new Point2;

	fs >>buffer; // FRAME
	if(strcmp(buffer, "FRAME")){
		fs.close();
		delete platform;
		return NULL;
	}

	fs >>buffer; // FRAME file_name
	platform->frame =loadFrame(buffer, cache);
	if(!platform->frame){

		fs.close();
		delete platform;
		return NULL;
	}

	fs >>buffer; // TEXTURE
	if(strcmp(buffer, "TEXTURE")){
		fs.close();
		delete platform;
		return NULL;
	}

	fs >>buffer; //  TEXTURE name
	platform->texture =loadTexture(buffer, cache);
	if(!platform->texture){
		fs.close();
		delete platform;
		return NULL;
	}

	fs >>buffer; // MATERIAL
	if(strcmp(buffer, "MATERIAL")){
		fs.close();
		delete platform;
		return NULL;
	}
	fs >>buffer;
	platform->material =getMaterial(buffer);

	fs.close();

	// create entry
//	entry =new Entry;
//	entry->pointer =(void*)platform;
//	entry->name =new char[strlen(buffer)+1];
//	if(!strcpy(entry->name, name)){
//		delete entry;
//		return NULL;
//	}
//	platforms.push_back(entry);
	return platform;
}

Texture* loadTexture(char* name, bool cache){

	Texture* texture;
	char buffer[256];
//	Entry* entry;

	// search if this platform exists
//	platform =(Platform*)findEntry(&platforms, name);
//	if(platform)
//		return platform;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, textures_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "texture")){
		fs.close();
		return NULL;
	}
	texture =new Texture;

	fs >>buffer; // TGA
	if(strcmp(buffer, "TGA")){
		fs.close();
		delete texture;
		return NULL;
	}
	fs >>buffer;
	if(strcmp(buffer, "NONE")==0){
		texture->tex =0;
	}
	else{
		texture->tex =loadTextureTGA(buffer, cache);
		if(texture->tex==0){
			fs.close();
			delete texture;
			return NULL;
		}
	}
	fs >>buffer; // X
	if(strcmp(buffer, "X")){
		fs.close();
		delete texture;
		return NULL;
	}
	fs >>texture->texDx;
	fs >>buffer; // Y
	if(strcmp(buffer, "Y")){
		fs.close();
		delete texture;
		return NULL;
	}
	fs >>texture->texDy;

	fs >>buffer; // COLOR
	if(strcmp(buffer, "COLOR")){
		fs.close();
		delete texture;
		return NULL;
	}
	fs >>texture->R;
	fs >>texture->G;
	fs >>texture->B;

	return texture;
}

Polygon2* loadPolygon(char* name, bool cache){

	int i;
	char buffer[256];
	Polygon2* polygon;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, polygons_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs)
		return NULL;

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "polygon")){
		fs.close();
		return NULL;
	}
	polygon =new Polygon2;
	polygon->position =new Point2;

	fs >>buffer;	// VERTICES
	if(strcmp(buffer, "VERTICES")){
		fs.close();
		delete polygon;
		return NULL;
	}
	fs >>polygon->maxElem;
	polygon->nElem =polygon->maxElem;

	polygon->pList =new Point2*[polygon->nElem];
	for(i=0; i<polygon->nElem; i++){
		polygon->pList[i] =new Point2;
		fs >>polygon->pList[i]->x;
		fs >>polygon->pList[i]->y;
	}

	fs >>buffer; // TEXTURE
	if(strcmp(buffer, "TEXTURE")){
		fs.close();
		delete polygon;
		return NULL;
	}
	fs >>buffer; //  TEXTURE name
	polygon->texture =loadTexture(buffer, cache);
	if(!polygon->texture){
		fs.close();
		delete polygon;
		return NULL;
	}
	polygon->box =createBoundingBox(polygon);

	return polygon;
}

Frame* loadFrame(char* name, bool cache){

	int vert_num, i;
	Polygon2* p_tmp;
	Entry* entry;
	char buffer[256];
	Frame* frame;

	// search if this platform exists
	if(cache){
		frame =(Frame*)findEntry(&frames, name);
		if(frame)
			return frame;
	}

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, frames_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs)
		return NULL;

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "frame")){
		fs.close();
		return NULL;
	}
	frame =new Frame;

	fs >>buffer;	// BOX
	if(strcmp(buffer, "BOX")){
		fs.close();
		delete frame;
		return NULL;
	}
//	fs >>vert_num;
	vert_num =2;
	p_tmp =new Polygon2(vert_num);
	for(i=0; i<vert_num; i++){

		fs >>p_tmp->pList[i]->x;
		fs >>p_tmp->pList[i]->y;
		p_tmp->nElem++;
	}
	// find box
	frame->box =createBoundingBox(p_tmp);
	delete p_tmp;

	fs >>buffer;	// BODY
	if(strcmp(buffer, "BODY")){
		fs.close();
		delete frame;
		return NULL;
	}
//	fs >>vert_num;
	p_tmp =new Polygon2(vert_num);
	for(i=0; i<vert_num; i++){

		fs >>p_tmp->pList[i]->x;
		fs >>p_tmp->pList[i]->y;
		p_tmp->nElem++;
	}
	// find body
	frame->body =createBoundingBox(p_tmp);
	delete p_tmp;
	
	fs.close();
	if(cache){
		// create entry
		entry =new Entry;
		entry->pointer =(void*)frame;
		entry->name =new char[strlen(name)+1];
		if(!strcpy(entry->name, name)){
			delete entry;
			return NULL;
		}
		frames.push_back(entry);
	}

	return frame;
}

Platform* loadFloor(char* name, bool cache){

//	Entry* entry;
	Platform* floor;
	char buffer[256];

	// search if this platform exists
//	floor =(Platform*)findEntry(&floors, name);
//	if(floor)
//		return floor;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, floors_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "floor")){
		fs.close();
		return NULL;
	}
	floor =new Platform;
	floor->position =new Point2;

	fs >>buffer; // FRAME
	if(strcmp(buffer, "FRAME")){
		fs.close();
		delete floor;
		return NULL;
	}

	fs >>buffer; // FRAME name
	floor->frame =loadFrame(buffer, cache);
	if(!floor->frame){

		fs.close();
		delete floor;
		return NULL;
	}

	fs >>buffer; // TEXTURE
	if(strcmp(buffer, "TEXTURE")){
		fs.close();
		delete floor;
		return NULL;
	}

	fs >>buffer; //  TEXTURE name
	floor->texture =loadTexture(buffer, cache);
	if(!floor->texture->tex){
		fs.close();
		delete floor;
		return NULL;
	}

	fs >>buffer; // MATERIAL
	if(strcmp(buffer, "MATERIAL")){
		fs.close();
		delete floor;
		return NULL;
	}
	fs >>buffer;
	floor->material =getMaterial(buffer);

    fs.close();
	// create entry
//	entry =new Entry;
//	entry->pointer =(void*)floor;
//	entry->name =new char[strlen(name)+1];
//	if(!strcpy(entry->name, name)){
//		delete entry;
//		return NULL;
//	}
//	floors.push_back(entry);
	return floor;
}

Animation* loadAnimation(char* name, bool cache){

	Animation* animation;
//	Entry* entry;
	int i;
	char buffer[256];

	// search if this platform exists
//	animation =(Animation*)findEntry(&animations, name);
//	if(animation)
//		return animation;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, animations_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs)
		return NULL;

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "animation")){
		fs.close();
		return NULL;
	}
	animation =new Animation;
	animation->begin_time =0;
	animation->cur_frame =0;

	fs >>buffer;	// FPS
	if(strcmp(buffer, "FPS")){
		fs.close();
		delete animation;
		return NULL;
	}
	fs >>animation->fps;
	fs >>buffer;	// FRAMES
	if(strcmp(buffer, "FRAMES")){
		fs.close();
		delete animation;
		return NULL;
	}
	fs >>animation->nFrames;
	animation->frames =new Frame*[animation->nFrames];
	for(i=0; i<animation->nFrames; i++){
		animation->frames[i] =NULL;
	}
	animation->sprites =new Texture*[animation->nFrames];
	for(i=0; i<animation->nFrames; i++){
		animation->sprites[i] =NULL;
	}
	animation->sources =new Source*[animation->nFrames];
	for(i=0; i<animation->nFrames; i++){
		animation->sources[i] =NULL;
	}

	for(i=0; i<animation->nFrames; i++){

		fs >>buffer;	// SRC?
		if(strcmp(buffer, "SRC")==0){

			fs >>buffer;
			animation->sources[i] =loadSource(buffer, cache);
			if(!animation->sources[i]){
				fs.close();
				delete animation;
				return NULL;
			}
			fs >>buffer;
		}
		if(strcmp(buffer, "FRAME")){
			fs.close();
			delete animation;
			return NULL;
		}		
		fs >>buffer;	// FRAME name
		animation->frames[i] =loadFrame(buffer, cache);
		if(!animation->frames[i]){
			fs.close();
			delete animation;
			return NULL;
		}

		fs >>buffer;	// SPRITE
		if(strcmp(buffer, "SPRITE")){
			fs.close();
			delete animation;
			return NULL;
		}		
		fs >>buffer;	// SPRITE name		
		animation->sprites[i] =loadTexture(buffer, cache);
		if(!animation->sprites[i]){
			fs.close();
			delete animation;
			return NULL;
		}

/*
		animation->sprites[i] =new Texture;
		fs >>buffer;	// SPRITE name		
		animation->sprites[i]->tex =loadTextureTGA(buffer, cache);
		if(!animation->sprites[i]->tex){
			fs.close();
			delete animation;
			return NULL;
		}

		fs >>animation->sprites[i]->texDx;
		fs >>animation->sprites[i]->texDy;
*/
	}

	fs >>buffer;	// EXTRA
	if(!strcmp(buffer, "EXTRA")){
		
		fs >>buffer;
		animation->extra =loadAnimation(buffer, cache);
		if(!animation->extra){
			fs.close();
			delete animation;
			return NULL;
		}
	}
	fs.close();
	// create entry
//	entry =new Entry;
//	entry->pointer =(void*)animation;
//	entry->name =new char[strlen(name)+1];
//	if(!strcpy(entry->name, name)){
//		delete entry;
//		return NULL;
//	}
//	animations.push_back(entry);
	return animation;
}

Hunter* loadHunter(char* name, bool cache){

	Audio* audio =Audio::Instance();
	Hunter* hunter;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, characters_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "hunter")){
		fs.close();
		return NULL;
	}
	hunter =new Hunter();
	hunter->velocity =new Point2(0,0);
	hunter->position =new Point2;
	hunter->orientation =new Point2;
//	hunter->layer =LAYER_PLAYER;

	fs >>buffer; // RUN_SPEED
	if(strcmp(buffer, "RUN_SPEED")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->speed;

	fs >>buffer; // JUMP_SPEED
	if(strcmp(buffer, "JUMP_SPEED")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->jump_speed;

	fs >>buffer; // JUMP_MULT
	if(strcmp(buffer, "JUMP_MULT")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->jump_mult;

	fs >>buffer; // MIRRORED
	if(strcmp(buffer, "MIRRORED")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->mirrored;

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_stand =loadAnimation(buffer, cache);
	if(!hunter->ani_stand){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_run =loadAnimation(buffer, cache);
	if(!hunter->ani_run){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_jump =loadAnimation(buffer, cache);
	if(!hunter->ani_jump){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_fall =loadAnimation(buffer, cache);
	if(!hunter->ani_fall){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_shoot =loadAnimation(buffer, cache);
	if(!hunter->ani_shoot){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_aim_up =loadAnimation(buffer, cache);
	if(!hunter->ani_aim_up){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_aim_down =loadAnimation(buffer, cache);
	if(!hunter->ani_aim_down){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_shoot_up =loadAnimation(buffer, cache);
	if(!hunter->ani_shoot_up){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_shoot_down =loadAnimation(buffer, cache);
	if(!hunter->ani_shoot_down){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_dead =loadAnimation(buffer, cache);
	if(!hunter->ani_dead){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	hunter->ani_reload =loadAnimation(buffer, cache);
	if(!hunter->ani_reload){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // SOURCE
	if(strcmp(buffer, "SOURCE")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // name
	hunter->src_shoot =loadSource(buffer, cache);
	if(!hunter->src_shoot){
		fs.close();
		delete hunter;
		return NULL;
	}

	fs >>buffer; // SOURCE
	if(strcmp(buffer, "SOURCE")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // name
	hunter->src_death =loadSource(buffer, cache);
	if(!hunter->src_death){
		fs.close();
		delete hunter;
		return NULL;
	}
	audio->genSource(&(hunter->src_death->id));

	fs >>buffer; // HEAD_LEVEL
	if(strcmp(buffer, "HEAD_LEVEL")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->head_level;

	fs >>buffer; // SHOOTING_LEVEL
	if(strcmp(buffer, "SHOOTING_LEVEL")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->shooting_level;

	fs >>buffer; // SHOOTING_LEVEL_UP
	if(strcmp(buffer, "SHOOTING_LEVEL_UP")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->shooting_level_up;

	fs >>buffer; // SHOOTING_LEVEL_DOWN
	if(strcmp(buffer, "SHOOTING_LEVEL_DOWN")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->shooting_level_down;


	fs >>buffer; // SHOOT_FX
	if(strcmp(buffer, "SHOOT_FX")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>buffer; // UP
	if(strcmp(buffer, "UP")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->u_correct;
	fs >>buffer; // STRAIGHT
	if(strcmp(buffer, "STRAIGHT")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->s_correct;
	fs >>buffer; // DOWN
	if(strcmp(buffer, "DOWN")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->d_correct;
	fs >>buffer; // DIE_JUMP
	if(strcmp(buffer, "DIE_JUMP")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->die_jump;

	fs >>buffer; // AMMO
	if(strcmp(buffer, "AMMO")){
		fs.close();
		delete hunter;
		return NULL;
	}
	fs >>hunter->ammo;
	hunter->max_ammo =hunter->ammo;

    fs.close();
	return hunter;
}

Kolobok* loadKolobok(char* name, bool cache){

	Kolobok* kolobok;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, characters_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "kolobok")){
		fs.close();
		return NULL;
	}
	kolobok =new Kolobok;
	kolobok->velocity =new Point2(0,0);
	kolobok->orientation =new Point2;
	kolobok->position =new Point2;
	kolobok->ai =new AI;

	fs >>buffer; // JUMP_SPEED
	if(strcmp(buffer, "JUMP_SPEED")){
		fs.close();
		delete kolobok;
		return NULL;
	}
	fs >>kolobok->jump_speed;

	fs >>buffer; // SPEED
	if(strcmp(buffer, "SPEED")){
		fs.close();
		delete kolobok;
		return NULL;
	}
	fs >>kolobok->speed;

	fs >>buffer; // ANTIGRAVITATOR
	if(strcmp(buffer, "ANTIGRAVITATOR")){
		fs.close();
		delete kolobok;
		return NULL;
	}
	fs >>kolobok->antigravitator;

	fs >>buffer; // CIRCLE
	if(strcmp(buffer, "CIRCLE")){

		fs.close();
		delete kolobok;
		return NULL;
	}
	fs >>buffer;
	kolobok->circle =loadCircle(buffer, cache);
	if(!kolobok->circle){

		fs.close();
		delete kolobok;
		return NULL;
	}

	return kolobok;
}

Cloud* loadCloud(char* name, bool cache){

	Cloud* cloud;

	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, clouds_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "cloud")){
		fs.close();
		return NULL;
	}
	cloud =new Cloud;
	cloud->position =new Point2;

	fs >>buffer; // SPEED
	if(strcmp(buffer, "SPEED")){
		fs.close();
		delete cloud;
		return NULL;
	}
	fs >>cloud->speed;

	fs >>buffer; // RECT
	if(strcmp(buffer, "RECT")){
		fs.close();
		delete cloud;
		return NULL;
	}
	cloud->rect =new Rect;
	fs >>cloud->rect->xLo;
	fs >>cloud->rect->yLo;
	fs >>cloud->rect->xHi;
	fs >>cloud->rect->yHi;

	fs >>buffer; // TEXTURE
	if(strcmp(buffer, "TEXTURE")){
		fs.close();
		delete cloud;
		return NULL;
	}
	fs >>buffer;
	cloud->texture =loadTexture(buffer, cache);
	if(!cloud->texture){
		fs.close();
		delete cloud;
		return NULL;
	}

	return cloud;
}

Zomby* loadZomby(char* name, bool cache){

	int i;
	Zomby* zomby;
	char buffer[256];
/*
	Entry* entry;
	// search if this platform exists
	if(cache){
		Zomby* zomby_t =static_cast<Zomby*>(findEntry(&zombies, name));
		if(zomby_t){

			zomby =new Zomby;
			*zomby =*zomby_t;
			return zomby;
		}
	}
*/
	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, characters_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "zomby")){
		fs.close();
		return NULL;
	}
	zomby =new Zomby;
	zomby->velocity =new Point2(0,0);
	zomby->position =new Point2;
	zomby->orientation =new Point2;
	zomby->ai =new AI;

	fs >>buffer; // RUN_SPEED
	if(strcmp(buffer, "RUN_SPEED")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>zomby->speed;

	fs >>buffer; // MIRRORED
	if(strcmp(buffer, "MIRRORED")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>zomby->mirrored;

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_stand =loadAnimation(buffer, cache);
	if(!zomby->ani_stand){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_run =loadAnimation(buffer, cache);
	if(!zomby->ani_run){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_fall =loadAnimation(buffer, cache);
	if(!zomby->ani_fall){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_dead =loadAnimation(buffer, cache);
	if(!zomby->ani_dead){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_rot =loadAnimation(buffer, cache);
	if(!zomby->ani_dead){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_bite =loadAnimation(buffer, cache);
	if(!zomby->ani_bite){
		fs.close();
		delete zomby;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete zomby;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	zomby->ani_kick =loadAnimation(buffer, cache);
	if(!zomby->ani_kick){
		fs.close();
		delete zomby;
		return NULL;
	}

	bool is_bite;
	zomby->bite =new Point2*[zomby->ani_bite->nFrames];
	fs >>buffer; // BITE
	if(strcmp(buffer, "BITE")){
		fs.close();
		delete zomby;
		return NULL;
	}

	for(i=0; i<zomby->ani_bite->nFrames; i++){

		fs >>is_bite;
		if(is_bite){

			zomby->bite[i] =new Point2;
			fs >>zomby->bite[i]->x;
			fs >>zomby->bite[i]->y;
		}
		else
		{
			zomby->bite[i] =NULL;
			fs >>is_bite;
			fs >>is_bite;
		}
	}

	bool is_kick;
	zomby->kick =new Point2*[zomby->ani_kick->nFrames];
	fs >>buffer; // KICK
	if(strcmp(buffer, "KICK")){
		fs.close();
		delete zomby;
		return NULL;
	}

	for(i=0; i<zomby->ani_kick->nFrames; i++){

		fs >>is_kick;
		if(is_kick){

			zomby->kick[i] =new Point2;
			fs >>zomby->kick[i]->x;
			fs >>zomby->kick[i]->y;
		}
		else
		{
			zomby->kick[i] =NULL;
			fs >>is_kick;
			fs >>is_kick;
		}
	}

	int rnd =rand()%20;		//? constatnt?
	zomby->speed -=zomby->speed*((float)rnd/100.0f);
	zomby->ani_run->fps -=zomby->ani_run->fps*((float)rnd/100.0f);

    fs.close();
/*
	if(cache){
		// create entry
		entry =new Entry;
		entry->pointer =static_cast<void*>(zomby);
		entry->name =new char[strlen(name)+1];
		if(!strcpy(entry->name, name)){
			delete entry;
			return NULL;
		}
		zombies.push_back(entry);
	}
*/
	return zomby;
}

int loadSources(char* name, bool cache, Source*** sources, int* num){

	char buffer[256];
	int i;

	sprintf(buffer, "%s%s%s", "./", sources_path, name);
	ifstream fs(buffer);
	if(!fs){
		return 0;
	}

	fs >>*num;
	*sources =new Source*[*num];
	for(i=0; i<*num; i++){

		fs >>buffer;
		(*sources)[i] =loadSource(buffer, cache);
		if(!(*sources)[i]){

			fs.close();
			return 0;
		}
	}

	fs.close();
	return 1;
}

Bird* loadBird(char* name, bool cache){

	Bird* bird;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, characters_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "bird")){
		fs.close();
		return NULL;
	}
	bird =new Bird;
	bird->velocity =new Point2(0,0);
	bird->position =new Point2;
	bird->orientation =new Point2;
	bird->ai =new AI;

	fs >>buffer; // RUN_SPEED
	if(strcmp(buffer, "RUN_SPEED")){
		fs.close();
		delete bird;
		return NULL;
	}
	fs >>bird->speed;

//	fs >>buffer; // JUMP_SPEED
//	if(strcmp(buffer, "JUMP_SPEED")){
//		fs.close();
//		delete zomby;
//		return NULL;
//	}
//	fs >>zomby->jump_speed;

	fs >>buffer; // MIRRORED
	if(strcmp(buffer, "MIRRORED")){
		fs.close();
		delete bird;
		return NULL;
	}
	fs >>bird->mirrored;

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete bird;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	bird->ani_still =loadAnimation(buffer, cache);
	if(!bird->ani_still){
		fs.close();
		delete bird;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete bird;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	bird->ani_move =loadAnimation(buffer, cache);
	if(!bird->ani_move){
		fs.close();
		delete bird;
		return NULL;
	}

	fs >>buffer; // ANIMATION
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete bird;
		return NULL;
	}
	fs >>buffer; // ANIMATION name
	bird->ani_dead =loadAnimation(buffer, cache);
	if(!bird->ani_dead){
		fs.close();
		delete bird;
		return NULL;
	}

	int rnd =rand()%20;		//? constatnt?
	bird->speed -=bird->speed*((float)rnd/100.0f);
	bird->ani_move->fps -=bird->ani_move->fps*((float)rnd/100.0f);

    fs.close();
	return bird;
}

Slope* loadSlope(char* name, bool cache){

	Slope* slope;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, slopes_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "slope")){
		fs.close();
		return NULL;
	}
	slope =new Slope;
	slope->position =new Point2;

	fs >>buffer; // LO
	if(strcmp(buffer, "LO")){
		fs.close();
		delete slope;
		return NULL;
	}
	slope->pLo =new Point2;
	fs >>slope->pLo->x;
	fs >>slope->pLo->y;

	fs >>buffer; // HI
	if(strcmp(buffer, "HI")){
		fs.close();
		delete slope;
		return NULL;
	}
	slope->pHi =new Point2;
	fs >>slope->pHi->x;
	fs >>slope->pHi->y;

	fs >>buffer; // LO_PH
	if(strcmp(buffer, "LO_PH")){
		fs.close();
		delete slope;
		return NULL;
	}
	slope->pLo_ph =new Point2;
	fs >>slope->pLo_ph->x;
	fs >>slope->pLo_ph->y;

	fs >>buffer; // HI_PH
	if(strcmp(buffer, "HI_PH")){
		fs.close();
		delete slope;
		return NULL;
	}
	slope->pHi_ph =new Point2;
	fs >>slope->pHi_ph->x;
	fs >>slope->pHi_ph->y;

	fs >>buffer; // TEXTURE
	if(strcmp(buffer, "TEXTURE")){
		fs.close();
		delete slope;
		return NULL;
	}

	fs >>buffer; //  TEXTURE name
	slope->texture =loadTexture(buffer, cache);
	if(!slope->texture){
		fs.close();
		delete slope;
		return NULL;
	}

	fs >>buffer; // MATERIAL
	if(strcmp(buffer, "MATERIAL")){
		fs.close();
		delete slope;
		return NULL;
	}
	fs >>buffer;
	slope->material =getMaterial(buffer);

	return slope;
}

Fx* loadFx(char* name, bool cache){

	Fx* fx;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, effects_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "fx")){
		fs.close();
		return NULL;
	}
	fx =new Fx;

	fs >>buffer; // TYPE 
	if(strcmp(buffer, "TYPE")){
		fs.close();
		delete fx;
		return NULL;
	}
	fs >>buffer; // dirrected
	if(!strcmp(buffer, "dirrected")){
		fx->type =FX_DIRECTED;
	}
	else if(!strcmp(buffer, "centered")){
		fx->type =FX_CENTERED;
	}
	else{
		fs.close();
		delete fx;
		return NULL;
	}

	fs >>buffer; // ANIMATION 
	if(strcmp(buffer, "ANIMATION")){
		fs.close();
		delete fx;
		return NULL;
	}
	fs >>buffer;
	fx->animation =loadAnimation(buffer, cache);
	if(!fx->animation){
		fs.close();
		delete fx;
		return NULL;
	}
	fx->animation->begin_time =0;

	fs >>buffer; // REPEAT 
	if(strcmp(buffer, "REPEAT")){
		fs.close();
		delete fx;
		return NULL;
	}
	fs >>fx->repeat;

	return fx;
}

Source* loadSource(char* name, bool cache){	//? we do not cache cources

	Audio* audio =Audio::Instance();
	Source* source;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, sources_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "source")){
		fs.close();
		return NULL;
	}
	source =new Source;

	fs >>buffer; // SOUND
	if(strcmp(buffer, "SOUND")){
		fs.close();
		delete source;
		return NULL;
	}
	fs >>buffer;
	if(!loadSound(buffer, &source->buffer, cache)){
		fs.close();
		delete source;
		return NULL;
	}

	fs >>buffer; // POSITION		//? no need to load position here (only z?)
	if(strcmp(buffer, "POSITION")){
		fs.close();
		delete source;
		return NULL;
	}
	fs >>source->x;
	fs >>source->y;
	fs >>source->z;

	fs >>buffer; // GAIN
	if(strcmp(buffer, "GAIN")){
		fs.close();
		delete source;
		return NULL;
	}
	fs >>source->gain;

	fs >>buffer; // LOOP
	if(strcmp(buffer, "LOOP")){
		fs.close();
		delete source;
		return NULL;
	}
	fs >>source->loop;

	audio->genSource(&(source->id));

	return source;
}

Camera* loadCamera(char* name){

	Camera* camera;
	char buffer[256];

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, data_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "camera")){
		fs.close();
		return NULL;
	}
	camera =new Camera;

	fs >>buffer; // WIDTH
	if(strcmp(buffer, "WIDTH")){
		fs.close();
		delete camera;
		return NULL;
	}
	fs >>camera->width;

	fs >>buffer; // HEIGHT
	if(strcmp(buffer, "HEIGHT")){
		fs.close();
		delete camera;
		return NULL;
	}
	fs >>camera->height;

	fs >>buffer; // NEAR
	if(strcmp(buffer, "NEAR")){
		fs.close();
		delete camera;
		return NULL;
	}
	fs >>camera->frustum_near;

	fs >>buffer; // FAR
	if(strcmp(buffer, "FAR")){
		fs.close();
		delete camera;
		return NULL;
	}
	fs >>camera->frustum_far;

	return camera;
}

Circle* loadCircle(char* name, bool cache){

//	Entry* entry;
	Circle* circle;
	char buffer[256];

	// search if this platform exists
//	floor =(Platform*)findEntry(&floors, name);
//	if(floor)
//		return floor;

	buffer[0] ='.';
	buffer[1] ='/';
	buffer[2] =0;
	strcat(buffer, circles_path);
	strcat(buffer, name);

	ifstream fs(buffer);
	if(!fs){
		return NULL;
	}

	fs >>buffer; // OBJECT
	if(strcmp(buffer, "OBJECT")){
		fs.close();
		return NULL;
	}
	fs >>buffer; // OBJECT name
	if(strcmp(buffer, "circle")){
		fs.close();
		return NULL;
	}
	circle =new Circle;
	circle->position =new Point2;

	while(!fs.eof()){
		fs >>buffer;
		if(strcmp(buffer, "RADIUS")==0){

			fs >>circle->radius;
		}
		else if(strcmp(buffer, "RADIUS_PH")==0){

			fs >>circle->radius_ph;
		}
		else if(strcmp(buffer, "TEXTURE")==0){

			fs >>buffer; //  TEXTURE name
			circle->texture =loadTexture(buffer, cache);
			if(!circle->texture){
				fs.close();
				delete circle;
				return NULL;
			}
		}
		else if(strcmp(buffer, "LOD")==0){
			fs >>circle->LOD;
		}
		else if(strcmp(buffer, "MATERIAL")==0){

			fs >>buffer;
			if(strcmp(buffer, "ground")==0){
				circle->material =MAT_GROUND;
			}
		}	
	}

    fs.close();
	// create entry
//	entry =new Entry;
//	entry->pointer =(void*)floor;
//	entry->name =new char[strlen(name)+1];
//	if(!strcpy(entry->name, name)){
//		delete entry;
//		return NULL;
//	}
//	floors.push_back(entry);
	return circle;
}

int loadConfig(char* name){

	char buffer[256];
	Game* game =Game::Instance();

	ifstream fs(name);
	if(!fs){
		return -1;
	}

	while(!fs.eof()){

		fs >>buffer;
		if(!strcmp(buffer, "CLOUDS")){
			fs >>buffer;
			if(!strcpy(clouds_path, buffer)){
				fs.close();
				return -1;
			}
		}else
		if(!strcmp(buffer, "DATA")){
			fs >>buffer;
			if(!strcpy(data_path, buffer)){
				fs.close();
				return -1;
			}
		}
//		else if(!strcmp(buffer, "SOUND")){
//			fs >>sound;
//		}
		else if(!strcmp(buffer, "ANIMATIONS")){
			fs >>buffer;
			if(!strcpy(animations_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "FLOORS")){
			fs >>buffer;
			if(!strcpy(floors_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "FRAMES")){
			fs >>buffer;
			if(!strcpy(frames_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "PLATFORMS")){
			fs >>buffer;
			if(!strcpy(platforms_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "SPRITES")){
			fs >>buffer;
			if(!strcpy(sprites_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "TEXTURES")){
			fs >>buffer;
			if(!strcpy(textures_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "SLOPES")){
			fs >>buffer;
			if(!strcpy(slopes_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "CIRCLES")){
			fs >>buffer;
			if(!strcpy(circles_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "CHARACTERS")){
			fs >>buffer;
			if(!strcpy(characters_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "SOUNDS")){
			fs >>buffer;
			if(!strcpy(sounds_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "SOURCES")){
			fs >>buffer;
			if(!strcpy(sources_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "EFFECTS")){
			fs >>buffer;
			if(!strcpy(effects_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "COMPOSITES")){
			fs >>buffer;
			if(!strcpy(composites_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "POLYGONS")){
			fs >>buffer;
			if(!strcpy(polygons_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "AI")){
			fs >>buffer;
			if(!strcpy(ai_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "RESPAWNS")){
			fs >>buffer;
			if(!strcpy(respawns_path, buffer)){
				fs.close();
				return -1;
			}
		}
		else if(!strcmp(buffer, "D_TOUCH")){
			fs >>D_TOUCH;
		}
		else if(!strcmp(buffer, "STAND_TEST")){
			fs >>STAND_TEST;
		}
		else if(!strcmp(buffer, "LOGIC_CYCLE_TIME")){
			fs >>LOGIC_CYCLE_TIME;
		}
		else if(!strcmp(buffer, "MAX_LOGIC_CYCLE_TIME")){
			fs >>MAX_LOGIC_CYCLE_TIME;
		}
		else if(!strcmp(buffer, "MAPPING")){
			fs >>buffer;
			if(!strcmp(buffer, "BILINEAR")){
				game->trilinear =false;
			}
			else if(!strcmp(buffer, "TRILINEAR")){
				game->trilinear =true;
			}
		}
		else if(!strcmp(buffer, "KEYS")){
			fs >>buffer;
			if(!strcpy(buffer, "UP")){
				fs.close();
				return -1;
			}
			fs >>game->key_up;

			fs >>buffer;
			if(!strcpy(buffer, "DOWN")){
				fs.close();
				return -1;
			}
			fs >>game->key_down;

			fs >>buffer;
			if(!strcpy(buffer, "LEFT")){
				fs.close();
				return -1;
			}
			fs >>game->key_left;

			fs >>buffer;
			if(!strcpy(buffer, "RIGHT")){
				fs.close();
				return -1;
			}
			fs >>game->key_right;

			fs >>buffer;
			if(!strcpy(buffer, "ATTACK")){
				fs.close();
				return -1;
			}
			fs >>game->key_attack;

			fs >>buffer;
			if(!strcpy(buffer, "SPECIAL")){
				fs.close();
				return -1;
			}
			fs >>game->key_special;
		}
		else{
			fs.close();
			return -1;
		}
	}

	fs.close();
	return 0;
}

unsigned int loadTextureTGA(char* name, bool cache)
{
	Entry* entry;
	void* pointer;
	GLuint tex =0;
	Game* game =Game::Instance();
	char buffer[256];

	if(cache){
		pointer =findEntry(&textures, name);
		if(pointer){
			return (unsigned int)pointer;
		}
	}

	buffer[0] =0;
	strcat(buffer, textures_path);
	strcat(buffer, name);
	
	RTGA* TextureImage =new RTGA;

	if(TextureImage->loadTGA(buffer)!=TGA_GOOD){
		delete TextureImage;
		return 0;
	}

	glGenTextures(1, &tex);
	if(!tex){
		delete TextureImage;				// Free The Image Structure
		return 0;
	}

	glBindTexture(GL_TEXTURE_2D, tex);
	glTexImage2D (GL_TEXTURE_2D, 0, TextureImage->texFormat, TextureImage->imageWidth, TextureImage->imageHeight, 0, TextureImage->texFormat, GL_UNSIGNED_BYTE, TextureImage->imageData);
	if(game->trilinear){
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 4, TextureImage->imageWidth, TextureImage->imageHeight, TextureImage->texFormat, GL_UNSIGNED_BYTE, TextureImage->imageData);
	}
	else{
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	}
	delete TextureImage;				// Free The Image Structure

	if(cache){
		// create entry
		entry =new Entry;
		entry->pointer =(void*)tex;
		entry->name =new char[strlen(name)+1];
		if(!strcpy(entry->name, name)){
			delete entry;
			return 0;
		}		
		textures.push_back(entry);
	}

	return tex;
}

bool loadSound(char* name, unsigned int* bfr, bool cache)
{
	Audio* audio =Audio::Instance();
	Entry* entry;
	void* pointer;
	char buffer[256];

	if(cache){
		pointer =findEntry(&sounds, name);
		if(pointer){
			*bfr =(unsigned int)pointer;
			return true;
		}
	}

	buffer[0] =0;
	strcat(buffer, sounds_path);
	strcat(buffer, name);
	
	audio->loadWave(buffer, bfr);

	if(cache){
		// create entry
		entry =new Entry;
		entry->pointer =(void*)*bfr;
		entry->name =new char[strlen(name)+1];
		if(!strcpy(entry->name, name)){
			delete entry;
			return false;
		}
		sounds.push_back(entry);
	}

	return true;
}

void clearIO(){

	Audio* audio =Audio::Instance();

	while(!frames.empty()){

		delete frames.back();
		frames.pop_back();
	}

	while(!textures.empty()){

		glDeleteTextures(1, (unsigned int*)&(textures.back()->pointer));
		textures.back()->pointer =NULL;
		delete textures.back();
		textures.pop_back();
	}

	while(!sounds.empty()){

		audio->deleteBuffer((unsigned int*)&(sounds.back()->pointer));
		sounds.back()->pointer =NULL;
		delete sounds.back();
		sounds.pop_back();
	}
}




